package main

import (
	"fmt"
	"strconv"
)

/**
Map 集合是无序的 key-value 数据结构。

Map 集合中的 key / value 可以是任意类型，但所有的 key 必须属于同一数据类型，所有的 value 必须属于同一数据类型，key 和 value 的数据类型可以不相同。
不同于切片根据索引查找值，map类型是根据key查找值。

map 是引用类型，声明语法：var map_name map[key_type]value_type
map的键是无序的
map的键不能重复

*/
func main() {

	info := make(map[string]string)
	info["name"] = "yuan"
	info["age"] = "23"
	fmt.Println(info) // map[age:23 name:yuan]

	// 直接声明赋值

	rating := map[string]float32{"C": 95, "go": 94.5}
	rating["php"] = 80 //追加元素
	fmt.Println("C的值是", rating["C"])
	/* map 插入 key-value 对，各个国家对应的首都 */
	for key := range rating {
		fmt.Println(key, "is", rating[key]) //通过key访问值
	}
	/* 查看元素在集合中是否存在 */
	phpVal, ok := rating["php"]
	if ok {
		fmt.Println("exist the phpVal is", phpVal)
	} else {
		fmt.Println("not exist")
	}

	// 定义 变量strMap
	var strMap map[int]string // 没有默认空间
	// 进行初始化
	strMap = make(map[int]string)

	// 给map 赋值
	for i := 0; i < 5; i++ {
		strMap[i] = "迈莫coding" + strconv.Itoa(i)
	}

	// 打印出map值
	for k, v := range strMap {
		fmt.Println(k, ":", v) //循环访问所有键值
	}
	//打印指定map的单个键值
	fmt.Println("打印指定map的单个键值", strMap[0])

	// 打印出map 长度
	fmt.Println(len(strMap))
	//编辑和删除
	strMap[4] = "t-mac" //// 键存在，则是更新键的值
	strMap[5] = "kobe"  // 键不存在，则是添加键值对
	delete(strMap, 0)   // map中的元素删除后，会重新索引，引起key和value对应的值变化,一个内置函数 delete()，用于删除容器内的元素,如果想清空一个map，最优方式即创建一个新的map！

	for i := range strMap {
		fmt.Println(i, "is", strMap[i])
	}
	strMap = make(map[int]string) //将mapName 重新初始化（mapName = make(map[int]string)），原来的map会被GC垃圾回收机制进行删除
	fmt.Println(strMap)

	//6.3.3、map 容量,和数组不同，map 可以根据新增的 key-value 动态的伸缩，因此它不存在固定长度或者最大限制，但是也可以选择标明 map 的初始容量 capacity，格式如下：make(map[keytype]valuetype, cap)

	map2 := make(map[string]float32, 100) //当 map 增长到容量上限的时候，如果再增加新的 key-value，map 的大小会自动加 1，所以出于性能的考虑，对于大的 map 或者会快速扩张的 map，即使只是大概知道容量，也最好先标明。
	map2["score"] = 99
	fmt.Println(map2)

	//6.3.4、map的灵活运用

	// 案例1
	data := map[string][]string{"hebei": []string{"廊坊市", "石家庄", "邯郸"}, "beijing": []string{"朝阳", "丰台", "海淀"}}
	fmt.Println(data["beijing"][1])

	// 案例2

	info2 := map[int]map[string]string{1001: {"name": "yuan", "age": "23"}, 1002: {"name": "alvin", "age": "33"}}
	fmt.Println(info2[1002]["name"])

	// 案例3
	infor2 := []map[string]string{{"name": "alvin1", "sid": "1001"}, {"name": "alvin2", "sid": "1002"}, {"sid": "1003", "name": "alvin3"}}
	fmt.Println(infor2[2]["sid"])
	//练习：
	// (1) 根据age的大小重新排序
	stus := []map[string]int{map[string]int{"age": 23}, map[string]int{"age": 33}, map[string]int{"age": 18}}
	fmt.Println(stus)
	// (2) 按照key即学号的大小顺序打印键值
	m1 := map[int]string{1001: "张三", 1100: "李四", 1010: "王五", 1008: "赵六"}
	fmt.Println(m1)
	// (3) 切片的反转
	s := []int{1, 2, 3, 5, 4}
	for i, j := 0, len(s)-1; i < j; i++ {
		j = len(s) - (i + 1)
		s[i], s[j] = s[j], s[i]
	}
	fmt.Println(s)
}
